from facility.contro_fn import MouseButton,KeyboardKey,InputController
from .setting import *
from facility.window_fn import Window
import time
from .base import Base
import math





def op_to_coordinate(start):
    direction = {
        'up_walk': (start[0], start[1] - 1),
        'up_run': (start[0], start[1] - 2),

        'up_right_walk': (start[0] + 1, start[1] - 1),
        'up_right_run': (start[0] + 2, start[1] - 2),

        'right_walk': (start[0] + 1, start[1]),
        'right_run': (start[0] + 2, start[1]),

        'right_down_walk':(start[0] + 1, start[1] + 1),
        'right_down_run': (start[0] + 2, start[1] + 2),

        'down_walk':(start[0], start[1] + 1),
        'down_run':  (start[0], start[1] + 2),

        'down_left_walk': (start[0] - 1, start[1] + 1),
        'down_left_run':  (start[0] - 2, start[1] + 2),

        'left_walk': (start[0] - 1, start[1]),
        'left_run':  (start[0] - 2, start[1]),

        'left_up_walk': (start[0] - 1, start[1] - 1),
        'left_up_run':   (start[0] - 2, start[1] - 2),
    }
    return direction

def coordinate_to_op(here,there):

    op = op_to_coordinate(here)

    if there not in op.values():raise Exception('can not go')

    idx = list(op.values()).index(there)

    return list(op.keys())[idx]







class A_Star:
    def __init__(self,data,start,end):
        self.data = data
        self.end = end
        self.open_list=list()
        self.close_list=[start]

    def _grow(self):
        start = self.close_list[-1]
        direction = {
            'up' : {
                'walk':(start[0], start[1] - 1),
                'run':(start[0], start[1] - 2)
            },
            'up_right': {
                'walk': (start[0] + 1, start[1] - 1),
                'run': (start[0] + 2, start[1] - 2)
            },
            'right': {
                'walk': (start[0] + 1, start[1]),
                'run': (start[0] + 2, start[1])
            },
            'right_down': {
                'walk': (start[0] + 1, start[1] + 1),
                'run': (start[0] + 2, start[1] + 2)
            },
            'down': {
                'walk': (start[0], start[1] + 1),
                'run': (start[0], start[1] + 2)
            },
            'down_left': {
                'walk': (start[0] - 1, start[1] + 1),
                'run': (start[0] - 2, start[1] + 2)
            },
            'left': {
                'walk': (start[0] - 1, start[1]),
                'run': (start[0] - 2, start[1])
            },
            'left_up': {
                'walk': (start[0] - 1, start[1] - 1),
                'run': (start[0] - 2, start[1] - 2)
            },
            }

        for i in direction.values():
            walk = i['walk']
            run = i['run']

            if self.legal(*walk) and walk not in self.close_list and walk not in self.open_list:
                self.open_list.append(walk)
                if self.legal(*run) and run not in self.close_list and run not in self.open_list:
                    self.open_list.append(run)





    def _find_min_f(self):
        value = [abs(i[0] - self.end[0]) + abs(i[1] - self.end[1]) for i in self.open_list]
        return  self.open_list[value.index(min(value))]



    def make_choice(self,callback=None):
        while self.end != self.close_list[-1]:
            self._grow()
            choice = self._find_min_f()
            self.open_list.remove(choice)
            self.close_list.append(choice)
            try:
                yield choice
            except:
                break

        if callback is not None:
            callback()



    def legal(self,x,y):
        try:
            return self.data[x,y] == '1'
        except:
            return self.data[x][y] == '1'





class Move(Base):


    def char_move(self,way,walk=False):

        if 'walk' in way or 'run' in way:
            way = way.split("_")
            walk = True if way.pop() == 'walk' else False
            way = "_".join(way)

        flag = 'run' if walk else 'walk'
        print(way,flag,end='\r')
        return {
            'up':self.up,
            'up_right':self.up_right,
            'right':self.right,
            'right_down':self.right_down,
            'down':self.down,
            'down_left':self.down_left,
            'left':self.left,
            'left_up':self.left_up,

        }[way](walk)


    def up(self,walk=False):
        self.window.focus_window()
        self.move(self.window.x_offset +CENTER_POINT[0], self.window.y_offset+CENTER_POINT[1] - 150,duration=0)


        if walk:
            self.click(MouseButton.LEFT)
        else:
            self.click(MouseButton.RIGHT)

    def up_right(self,walk=False):
        self.window.focus_window()
        self.move(self.window.x_offset  + CENTER_POINT[0] + 200, self.window.y_offset + CENTER_POINT[1]-150,duration=0)

        if walk:
            self.click(MouseButton.LEFT)
        else:
            self.click(MouseButton.RIGHT)

    def right(self,walk=False):
        self.window.focus_window()
        self.move(self.window.x_offset + CENTER_POINT[0] + 200, self.window.y_offset +CENTER_POINT[1]+10,duration=0)

        if walk:
            self.click(MouseButton.LEFT)
        else:
            self.click(MouseButton.RIGHT)

    def right_down(self,walk=False):
        self.window.focus_window()
        self.move(self.window.x_offset  + CENTER_POINT[0] + 200, self.window.y_offset + CENTER_POINT[1] + 150,duration=0)

        if walk:
            self.click(MouseButton.LEFT)
        else:
            self.click(MouseButton.RIGHT)



    def down(self,walk=False):
        self.window.focus_window()
        self.move(self.window.x_offset +CENTER_POINT[0], self.window.y_offset+CENTER_POINT[1] + 150,duration=0)

        if walk:
            self.click(MouseButton.LEFT)
        else:
            self.click(MouseButton.RIGHT)

    def down_left(self,walk=False):
        self.window.focus_window()
        self.move(self.window.x_offset  + CENTER_POINT[0] - 200, self.window.y_offset + CENTER_POINT[1] + 150,duration=0)

        if walk:
            self.click(MouseButton.LEFT)
        else:
            self.click(MouseButton.RIGHT)


    def left(self,walk=False):
        self.window.focus_window()
        self.move(self.window.x_offset + CENTER_POINT[0] - 200, self.window.y_offset + CENTER_POINT[1]+10,duration=0)


        if walk:
            self.click(MouseButton.LEFT)
        else:
            self.click(MouseButton.RIGHT)


    def left_up(self,walk=False):
        self.window.focus_window()
        self.move(self.window.x_offset  + CENTER_POINT[0] - 200, self.window.y_offset + CENTER_POINT[1] - 150,duration=0)

        if walk:
            self.click(MouseButton.LEFT)
        else:
            self.click(MouseButton.RIGHT)




    def npc_transport(self,idx):
        self.window.focus_window()
        self.tap_key(KeyboardKey.KEY_1)
        self.left_up()
        time.sleep(0.5)
        self.move(self.window.x_offset+100, self.window.y_offset+20, duration=0.5)
        self.click(MouseButton.LEFT)


        idx = int(idx)

        if idx <100:
            row = math.ceil(idx / 3)
            col = idx % 3
            col = col if col != 0 else 3

            start = TRANS_PART_A_START
            self.move(self.window.x_offset + start[0] + (col - 1) * TRANS_OFFSET_X,
                      self.window.y_offset + start[1] + (row - 1) * TRANS_OFFSET_Y)

        if 100<= idx <200:
            idx -=100
            row = math.ceil(idx / 3)
            col = idx % 3
            col = col if col != 0 else 3
            start = TRANS_PART_B_START

        if idx >=200:
            idx -= 200
            start = TRANS_PART_C_START
            row = math.ceil(idx / 3)
            col = idx % 3
            col = col if col != 0 else 3
            self.move(self.window.x_offset + start[0] + (col - 1) * TRANS_OFFSET_X,
                      self.window.y_offset + start[1] + (row - 1) * TRANS_OFFSET_Y)



        self.click(MouseButton.LEFT)
        time.sleep(1.5)




    def ring_transport(self,x,y):
        self.window.focus_window()
        self.tap_key(KeyboardKey.KEY_ENTER)
        self.write('@传送 {} {}'.format(x,y))
        self.tap_key(KeyboardKey.KEY_ENTER)


    def a_start_goto_seq(self,start=None,dst=None,map_data=None):


        alg = A_Star(map_data, start, dst)
        seq = [start] + [i for i in alg.make_choice()]
        ops = list()

        there = seq.pop()

        while seq.__len__() > 0:
            here = seq.pop()
            try:
                op = coordinate_to_op(here, there)
                there = here
                ops.append(op)
            except:
                pass

        return ops





